package com.htfyun.serialport.uartservo.AX12_ServoUpdate;

import com.htfyun.serialport.uartservo.IServoReceivedSerialPacket;
import com.htfyun.serialport.utils.UsefulUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 单片机返回包如下:
 * FD FD ID 0x07 0x00 当前已写字节数(4个byte) 子命令(1个byte) CheckSum 共计11位
 * <p>
 * CheckSum = ~(ID + 0x07 + 0x00 + 当前已写字节数(4个byte) + 子命令(1个byte))
 * 如果计算结果大于 255，则后面字节的值设为校验码的值。
 */

public class AX12Update_ReceivedSerialPacket implements IServoReceivedSerialPacket {


    private static final byte[] header = new byte[]{(byte) 0xFD, (byte) 0xFD};

    public static final short PACKAGE_DATA_FIXED_LEN = 7;

    public static final int PACKAGE_SIZE = 11;

    private byte id;
    private byte checkSum;

    private int wroteDataLength;//已经写入了的数据大小

    private byte instruction;

    private final boolean isValid;

    public AX12Update_ReceivedSerialPacket(ByteBuffer byteBuffer) {
        isValid = parseByteBuffer(byteBuffer);
    }

    private boolean parseByteBuffer(ByteBuffer byteBuffer) {

        if (byteBuffer.capacity() != PACKAGE_SIZE) {
            return false;
        }

        byteBuffer.rewind();
        //小端模式存放
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);

        short header = byteBuffer.getShort();

        if (header != getHeaderShort()) {
            return false;
        }

        id = byteBuffer.get();

        short length = byteBuffer.getShort();
        if (length != PACKAGE_DATA_FIXED_LEN) {
            return false;
        }

        wroteDataLength = byteBuffer.getInt();

        instruction = byteBuffer.get();
        checkSum = byteBuffer.get();

        return checkSum();

    }

    private static short getHeaderShort() {
//        return (short) ((header[0] & 0xff) | ((header[1]  << 8) & 0xff00));
        ByteBuffer byteBuffer = getHeaderByteBuffer();
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        return byteBuffer.getShort();
    }

    public static byte[] getHeader() {
        return header;
    }

    public static ByteBuffer getHeaderByteBuffer() {
        return ByteBuffer.wrap(getHeader());
    }

    private boolean checkSum() {

        int checkSumInt = (getId() + PACKAGE_DATA_FIXED_LEN + getInstruction());
        int length = getWroteDataLength();
        for (int i = 0; i < 4; i++) {
            checkSumInt += (0xff & (length >> 8 * i));
        }

        checkSumInt = ~checkSumInt;

        byte checkSum = (byte) checkSumInt;

        return (checkSum == getCheckSum());
    }


    public byte getId() {
        return id;
    }

    public int getWroteDataLength() {
        return wroteDataLength;
    }

    public byte getInstruction() {
        return instruction;
    }

    public byte getCheckSum() {
        return checkSum;
    }

    @Override
    public boolean isValid() {
        return isValid;
    }

    public byte[] toBytes() {
        ByteBuffer byteBuffer = ByteBuffer.allocate(PACKAGE_SIZE);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.rewind();
        byteBuffer.put(header);
        byteBuffer.put(getId());
        byteBuffer.putShort(PACKAGE_DATA_FIXED_LEN);
        byteBuffer.putInt(getWroteDataLength());
        byteBuffer.put(getInstruction());
        byteBuffer.put(getCheckSum());
        return byteBuffer.array();
    }

    public AX12Update_instructionAttr getInstructionAttr() {

        for (AX12Update_instructionAttr attr : AX12Update_instructionAttr.values()) {
            if (attr.getInstruction() == getInstruction()) {
                return attr;
            }
        }
        return AX12Update_instructionAttr.none;
    }

    @Override
    public String toString() {
        return UsefulUtil.toHexString(toBytes()) + ", isValid = " + isValid;
    }
}
